home *** CD-ROM | disk | FTP | other *** search
/ Atari Mega Archive 2 / Atari Mega Archive CD - Volume 2.iso / minix / up1510b.tgz / up1510b / src / commands / find.c < prev    next >
C/C++ Source or Header  |  1990-07-23  |  13KB  |  620 lines

  1. /* find - look for files satisfying a predicat    Author: Erik Baalbergen */
  2.  
  3. /*
  4.    *** Check the switches in the SWITCHES section below. ***
  5.  
  6.    Differences from UNIX version 7 find(1):
  7.   * -name: no name allowed; only uid
  8.     e.g. find all core files: "find . -name core -a -print"
  9.   * -xdev: do not cross file system boundaries
  10.  
  11.    The "-atime" may not work well on Minix.
  12.    Please report bugs and suggestions to erikb@cs.vu.nl
  13. */
  14.  
  15.  
  16. #include <sys/types.h>
  17. #include <fcntl.h>
  18. #include <sys/stat.h>
  19. #include <stdio.h>
  20.  
  21. #define SHELL "/usr/bin/sh"
  22.  
  23. #define PLEN    256        /* maximum path length; overflows are not
  24.              * detected */
  25. #define DIRSIZ    16        /* size of a directory entry */
  26. #define MAXARG    256        /* maximum length for an argv */
  27. #define NPATHS    256        /* maximum number of paths in path-list */
  28. #define BSIZE  1024        /* bytes per block */
  29.  
  30. /*######################## DEFINITIONS ##############################*/
  31. #define SECS_PER_DAY    (24L * 60L * 60L)    /* check your planet */
  32.  
  33. struct exec {
  34.   int e_cnt;
  35.   char *e_vec[MAXARG];
  36. };
  37.  
  38. #define OP_NAME        1
  39. #define OP_PERM        2
  40. #define OP_TYPE        3
  41. #define OP_LINKS    4
  42. #define OP_USER        5
  43. #define OP_GROUP    6
  44. #define OP_SIZE        7
  45. #define OP_INUM        8
  46. #define OP_ATIME    9
  47. #define OP_MTIME    10
  48. #define OP_EXEC        11
  49. #define OP_OK        12
  50. #define OP_PRINT    13
  51. #define OP_NEWER    14
  52. #define OP_AND        15
  53. #define OP_OR        16
  54. #define OP_XDEV        17    /* do not cross file-system boundaries */
  55.  
  56. struct oper {
  57.   char *op_str;
  58.   int op_val;
  59. } ops[] = {
  60.   {    "name",        OP_NAME  },
  61.   {    "perm",        OP_PERM  },
  62.   {    "type",        OP_TYPE  },
  63.   {    "links",    OP_LINKS  },
  64.   {    "user",        OP_USER  },
  65.   {    "group",    OP_GROUP  },
  66.   {    "size",        OP_SIZE  },
  67.   {    "inum",        OP_INUM  },
  68.   {    "atime",    OP_ATIME  },
  69.   {    "mtime",    OP_MTIME  },
  70.   {    "exec",        OP_EXEC  },
  71.   {    "ok",        OP_OK  },
  72.   {    "print",    OP_PRINT  },
  73.   {    "newer",    OP_NEWER  },
  74.   {    "a",        OP_AND  },
  75.   {    "o",        OP_OR  },
  76.   {    "xdev",        OP_XDEV  },
  77.   {    0, 0  }
  78. };
  79.  
  80. #define EOI    -1
  81. #define NONE    0
  82. #define LPAR    20
  83. #define RPAR    21
  84. #define NOT    22
  85.  
  86. char *prog, *strcpy(), *Malloc(), *find_bin();
  87.  
  88. struct node {
  89.   int n_type;            /* any OP_ or NOT */
  90.   union {
  91.     char *n_str;
  92.     struct {
  93.         long n_val;
  94.         int n_sign;
  95.     } n_int;
  96.     struct exec *n_exec;
  97.     struct {
  98.         struct node *n_left, *n_right;
  99.     } n_opnd;
  100.   } n_info;
  101. };
  102. struct node *expr();
  103.  
  104. char **ipp;
  105. int tty;            /* fd for /dev/tty when using -ok */
  106. long current_time;
  107. int xdev_flag = 0;
  108. int devnr;
  109.  
  110. char *
  111.  Malloc(n)
  112. {
  113.   char *malloc(), *m;
  114.  
  115.   if ((m = malloc(n)) == 0) fatal("out of memory", "");
  116.   return m;
  117. }
  118.  
  119. char *
  120.  Salloc(s)
  121. char *s;
  122. {
  123.   return strcpy(Malloc(strlen(s) + 1), s);
  124. }
  125.  
  126. main(argc, argv)
  127. char *argv[];
  128. {
  129.   char *pathlist[NPATHS];
  130.   int pathcnt = 0;
  131.   register i;
  132.   struct node *pred;
  133.  
  134.   prog = *argv++;
  135.   while (--argc > 0 && lex(*argv) == NONE) pathlist[pathcnt++] = *argv++;
  136.   if (pathcnt == 0 || argc == 0)
  137.     fatal("Usage: path-list predicate-list", "");
  138.   ipp = argv;
  139.   time(¤t_time);
  140.   pred = expr(lex(*ipp));
  141.   if (lex(*++ipp) != EOI)
  142.     fatal("syntax error: garbage at end of predicate", "");
  143.   for (i = 0; i < pathcnt; i++) {
  144.     if (xdev_flag) xdev_flag = 2;
  145.     find(pathlist[i], pred, "");
  146.   }
  147.   exit(0);
  148. }
  149.  
  150. find(path, pred, last)
  151. char *path, *last;
  152. struct node *pred;
  153. {
  154.   char spath[PLEN], ent[DIRSIZ + 1];
  155.   struct stat st;
  156.   register char *send = spath;
  157.   FILE *fp, *fopen();
  158.  
  159.   if (path[1] == '\0' && *path == '/') {
  160.     *send++ = '/';
  161.     *send = '\0';
  162.   } else
  163.     while (*send++ = *path++) {
  164.     }
  165.  
  166.   if (stat(spath, &st) == -1)
  167.     nonfatal("can't get status of ", spath);
  168.   else {
  169.     switch (xdev_flag) {
  170.         case 0:
  171.         break;
  172.         case 1:
  173.         if (st.st_dev != devnr) return;
  174.         break;
  175.         case 2:        /* set current device number */
  176.         xdev_flag = 1;
  177.         devnr = st.st_dev;
  178.         break;
  179.     }
  180.  
  181.     (void) check(spath, &st, pred, last);
  182.     if ((st.st_mode & S_IFMT) == S_IFDIR) {
  183.         if ((fp = fopen(spath, "r")) == NULL) {
  184.             nonfatal("can't read directory ", spath);
  185.             return;
  186.         }
  187.         send[-1] = '/';
  188.         ent[DIRSIZ] = '\0';
  189.         while (fread(ent, DIRSIZ, 1, fp) == 1) {
  190.             if (!((*ent == '\0' && ent[1] == '\0')
  191.                   || (ent[2] == '.') &&
  192.                   (ent[3] == '\0'
  193.                    || (ent[3] == '.' && ent[4] == '\0'))
  194.                   )) {
  195.                 strcpy(send, ent + 2);
  196.                 find(spath, pred, ent + 2);
  197.             }
  198.         }
  199.         fclose(fp);
  200.     }
  201.   }
  202. }
  203.  
  204. check(path, st, n, last)
  205. char *path, *last;
  206. register struct stat *st;
  207. register struct node *n;
  208. {
  209.   switch (n->n_type) {
  210.       case OP_AND:
  211.     return check(path, st, n->n_info.n_opnd.n_left, last) &&
  212.         check(path, st, n->n_info.n_opnd.n_right, last);
  213.       case OP_OR:
  214.     return check(path, st, n->n_info.n_opnd.n_left, last) ||
  215.         check(path, st, n->n_info.n_opnd.n_right, last);
  216.       case NOT:
  217.     return !check(path, st, n->n_info.n_opnd.n_left, last);
  218.       case OP_NAME:
  219.     return smatch(last, n->n_info.n_str);
  220.       case OP_PERM:
  221.     if (n->n_info.n_int.n_sign < 0)
  222.         return st->st_mode == (int) n->n_info.n_int.n_val;
  223.     return(st->st_mode & 0777) == (int) n->n_info.n_int.n_val;
  224.       case OP_NEWER:
  225.     return st->st_mtime > n->n_info.n_int.n_val;
  226.       case OP_TYPE:
  227.     return(st->st_mode & S_IFMT) == n->n_info.n_int.n_val;
  228.       case OP_LINKS:
  229.     return ichk((long) (st->st_nlink), n);
  230.       case OP_USER:
  231.     return st->st_uid == n->n_info.n_int.n_val;
  232.       case OP_GROUP:
  233.     return st->st_gid == n->n_info.n_int.n_val;
  234.       case OP_SIZE:
  235.     return ichk((st->st_size == 0) ? 0L :
  236.             ((st->st_size - 1) / BSIZE + 1), n);
  237.       case OP_INUM:
  238.     return ichk((long) (st->st_ino), n);
  239.       case OP_ATIME:
  240.     return ichk(st->st_atime, n);
  241.       case OP_MTIME:
  242.     return ichk(st->st_mtime, n);
  243.       case OP_EXEC:
  244.       case OP_OK:
  245.     return execute(n->n_type, n->n_info.n_exec, path);
  246.       case OP_PRINT:
  247.     prints("%s\n", path);
  248.     return 1;
  249.       case OP_XDEV:    return 1;
  250. }
  251.   fatal("ILLEGAL NODE", "");
  252. }
  253.  
  254. ichk(val, n)
  255. long val;
  256. struct node *n;
  257. {
  258.   switch (n->n_info.n_int.n_sign) {
  259.       case 0:
  260.     return val == n->n_info.n_int.n_val;
  261.       case 1:
  262.     return val > n->n_info.n_int.n_val;
  263.       case -1:    return val < n->n_info.n_int.n_val;
  264. }
  265.   fatal("internal: bad n_sign", "");
  266. }
  267.  
  268. lex(str)
  269. char *str;
  270. {
  271.   if (str == 0) return EOI;
  272.   if (*str == '-') {
  273.     register struct oper *op;
  274.  
  275.     str++;
  276.     for (op = ops; op->op_str; op++)
  277.         if (strcmp(str, op->op_str) == 0) break;
  278.     return op->op_val;
  279.   }
  280.   if (str[1] == 0) {
  281.     switch (*str) {
  282.         case '(':
  283.         return LPAR;
  284.         case ')':
  285.         return RPAR;
  286.         case '!':    return NOT;
  287.     }
  288.   }
  289.   return NONE;
  290. }
  291.  
  292. struct node *
  293.  newnode(t)
  294. {
  295.   struct node *n = (struct node *) Malloc(sizeof(struct node));
  296.  
  297.   n->n_type = t;
  298.   return n;
  299. }
  300.  
  301. /*########################### PARSER ###################################*/
  302. /* Grammar:
  303.   expr : primary | primary OR expr;
  304.   primary : secondary | secondary AND primary | secondary primary;
  305.   secondary : NOT secondary | LPAR expr RPAR | simple;
  306.   simple : -OP args...
  307. */
  308. struct node *expr(), *primary(), *secondary(), *simple();
  309.  
  310. number(str, base, pl, ps)
  311. char *str;
  312. long *pl;
  313. int *ps;
  314. {
  315.   int up = '0' + base - 1;
  316.   long val = 0;
  317.  
  318.   *ps = ((*str == '-' || *str == '+') ? ((*str++ == '-') ? -1 : 1) : 0);
  319.   while (*str >= '0' && *str <= up) val = base * val + *str++ - '0';
  320.   if (*str) fatal("syntax error: illegal numeric value", "");
  321.   *pl = val;
  322. }
  323.  
  324. struct node *
  325.  expr(t)
  326. {
  327.   struct node *nd, *p, *nd2;
  328.  
  329.   nd = primary(t);
  330.   if ((t = lex(*++ipp)) == OP_OR) {
  331.     nd2 = expr(lex(*++ipp));
  332.     p = newnode(OP_OR);
  333.     p->n_info.n_opnd.n_left = nd;
  334.     p->n_info.n_opnd.n_right = nd2;
  335.     return p;
  336.   }
  337.   ipp--;
  338.   return nd;
  339. }
  340.  
  341. struct node *
  342.  primary(t)
  343. {
  344.   struct node *nd, *p, *nd2;
  345.  
  346.   nd = secondary(t);
  347.   if ((t = lex(*++ipp)) != OP_AND) {
  348.     ipp--;
  349.     if (t == EOI || t == RPAR || t == OP_OR) return nd;
  350.   }
  351.   nd2 = primary(lex(*++ipp));
  352.   p = newnode(OP_AND);
  353.   p->n_info.n_opnd.n_left = nd;
  354.   p->n_info.n_opnd.n_right = nd2;
  355.   return p;
  356. }
  357.  
  358. struct node *
  359.  secondary(t)
  360. {
  361.   struct node *n, *p;
  362.  
  363.   if (t == LPAR) {
  364.     n = expr(lex(*++ipp));
  365.     if (lex(*++ipp) != RPAR) fatal("syntax error, ) expected", "");
  366.     return n;
  367.   }
  368.   if (t == NOT) {
  369.     n = secondary(lex(*++ipp));
  370.     p = newnode(NOT);
  371.     p->n_info.n_opnd.n_left = n;
  372.     return p;
  373.   }
  374.   return simple(t);
  375. }
  376.  
  377. checkarg(arg)
  378. char *arg;
  379. {
  380.   if (arg == 0) fatal("syntax error, argument expected", "");
  381. }
  382.  
  383. struct node *
  384.  simple(t)
  385. {
  386.   struct node *p = newnode(t);
  387.   struct exec *e;
  388.   struct stat est;
  389.   long l;
  390.  
  391.   switch (t) {
  392.       case OP_TYPE:
  393.     checkarg(*++ip